﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

// std headers
#include <memory>

// qt headers
#include <QObject>

// custom headers
#include "GcsService.h"
#include "IProjectComponent.h"
#include "IDetailedProjectComponent.h"
#include "IParameter.gcs.h"
#include "Major.h"
#include "ComponentData.h"


template<typename T> class QList;
class QNetworkReply;
class QNetworkAccessManager;
class QNetworkRequest;

namespace gmep
{
    class IGmepCategoryInfo;
    class IGmepProjectSettingComponent;
}

namespace gmepgcs
{
    struct IParameter;
    struct IPerformanceCurveDefinition;
    struct IPerformanceCurve;
    struct ILegend; 
    struct ISpecification;
    
    template<typename TResult> class CustomReply;
    template<typename TData> class IPagedData;
    class CustomFileReply;
    class IEditingProjectComponent;
    class ProjectComponentExistingCheck;

    //class ChangedComponentsBean;
}

namespace gcs
{
    class IGcsViewOptions;
}
namespace gmepgcs
{
    class GCS_SERVICE_EXPORTS ProjectLocalComponentService : public QObject
    {
        Q_OBJECT

    private:
        explicit ProjectLocalComponentService();
        ProjectLocalComponentService(const ProjectLocalComponentService &) = default;
        ProjectLocalComponentService &operator=(const ProjectLocalComponentService &) = default;
        virtual ~ProjectLocalComponentService();
        
    public:
        static ProjectLocalComponentService *Get();

    public:
        IPagedData<std::vector<std::shared_ptr<IProjectComponent>>> GetComponents(
            const Major &major,
            const std::wstring & keyword,
            const std::wstring & categoryCode,
            const int32_t & page,
            const int32_t & pageSize) const;

        // 获取此分类下的实际构件个数
        int GetProjectComponentCountOfCategory(const std::wstring & projectId, const std::wstring & categoryCode);
        void GetProjectComponentCountOfCategory(const std::wstring & projectId, const std::vector<std::wstring>& vecCategoryCode, std::map<std::wstring, int>& mapComponentCount);

        std::shared_ptr<IDetailedProjectComponent> GetDetailedComponent(
            const std::wstring & projectId,
            const std::wstring & componentId,
            const int32_t & componentVersion) const;

        std::shared_ptr<ISpecification> GetSpecification(
            const std::wstring & projectId,
            const std::wstring & componentId,
            const int32_t & componentVersion,
            const std::wstring & specificationName) const;

        std::vector<std::shared_ptr<ISpecification>> GetSpecifications(
            const std::wstring & projectId,
            const std::wstring & componentId,
            const int32_t & componentVersion) const;

        std::vector<std::shared_ptr<ILegend>> GetLegends(const IDetailedProjectComponent* pDetailedComp);

        bool AddChosenLegendToLocal(const std::wstring &projectId, const std::wstring &enterpriseId, const std::wstring & categoryCode,
            ILegend* pLegend, const std::wstring& strTempPngFile, std::wstring& strNewPngFile, bool isPrivateEnv = false);

        // 编辑，返回编辑后的新version， 若原构件行dirtyflag 为0， 则newversion 为+1， 否则newversion不变
        bool SaveModifiedComponent(
            const std::wstring &projectId,
            const IEditingProjectComponent &component,int& compNewVersion, std::wstring& strError) const;
        // 编辑，返回编辑后的新version， 若原构件行dirtyflag 为0， 则newversion 为+1， 否则newversion不变（传参为 gmep::IGmepProjectSettingComponent）
        bool SaveModifiedComponent(
            const std::wstring &projectId,
            const gmep::IGmepProjectSettingComponent *pComponent, int& compNewVersion, std::wstring& strError);

        // 将从公共库添加后，下载这些项目构件到本地db
        bool SaveAddedComponentFromPublicToProjectDb(const std::wstring &projectId, const std::wstring& enterpriseId, std::map<std::wstring, ComponentInfos>& projectComponents);

        // 从公共库替换后 存到本地，清除dirtyFlag
        bool SaveReplacedComponentFromPublic(const std::wstring &projectId, const std::wstring& enterpriseId, const std::wstring &compId, const int iVersion);

        // 从本地删除该构件
        bool DeleteComponentFromLocal(const std::wstring &projectId, const std::wstring &compId, const int iVersion);

        // 同步
        bool SyncComponents(const std::wstring& projectId, const std::wstring& enterpriseId, const std::vector<IProjectComponent>& compVec, std::wstring& retSuccInfo);

        /// \brief 更新工作单元的旧族（2d平立侧构件有变化需重新载入族；若仅属性信息有变化，需重新设置其类型参数值）
        /// \param updatedComponents 待更新的构件列表 , bool 为true，则强制更新工作单元的实例，无需比较 familyversion
        /// \return 返回被更新的旧族数量
        int UpdateFamiliesInDocument(const std::vector<std::tuple<std::wstring, int, bool>>& updatedComponents);

        // 一键更新的实现移到这里：CmdSyncComponents， 下载所有构件， 并把工作单元使用的族重新加载好
        // 返回 下载成功的个数（不是工作单元重新更新/加载族的个数）
        // updatedFamiliesCountInDocCount 工作单元的族更新的个数
        // changeCountVec增删改个数
        int SyncComponentsByOneKey(const std::wstring &projectId, const bool isDocReadOnly, int& updatedFamiliesCountInDocCount, std::vector<int>& changeCountVec);
        // 更新此工作单元的旧族， 返回 工作单元的族更新的个数
        int UpdateAllOldFamiliesInDocument();

        // 上传删除成功后， 重新设置doc的familyId 和version 为0
        int UpdateSuccDeletedFamiliesInDocument(std::map<std::wstring, int> deletedSuccMap);

        // 对于下载的云端删除构件，需要设置id version为0， name 为_001
        int UpdateSyncedDeletedFamiliesInDocument(std::map<std::wstring, int> deletedIdMap);

        int ReplaceFamilyIdNameInDocument(const std::vector<std::tuple<std::wstring, std::wstring, std::wstring>>& uploadedComponents);

        /// \brief 从本地库检查该构件是否已经存在
        /// \return 返回是否已经存在
        bool SearchComponentNameIsExistFromLocal(const std::wstring &projectId, const IComponent& component);

        /// \brief 设备选型，调用构件坞产品库页面
        /// \param parent 父窗口
        /// \param projectId 项目id
        /// \param enterpriseId 企业库id
        /// \param categoryName 产品库构件类别页面名称
        /// \return 选型成功 true
        bool SendEquipmentSelectionInfo(QWidget * parent, const std::wstring& projectId, const std::wstring& enterpriseId, const std::wstring& categoryName);

        /// \brief 布置产品库设备
        /// \param projectComponents 公共库返回的构件列表
        /// \return  true 有需要布置的构件 false 不需要布置
       // bool PlaceEquipment(const std::vector<std::shared_ptr<gcs::ProjectComponent>>&  projectComponents);

        /// \brief 打开公共库窗口的Command定义：
        // showGcsGjwWindowCommand
       // isCollaboration     true为协同版，false为单机版
        // Location                                     // 显示主窗体后，着陆页的路径
            // component / all                          // 进入构件库页面
            // product / fans                           // 进入选风机页面
            // product / pumps                          // 进入选水泵页面
            // material / all                           // 进入材料库页面
        void ShowGcsGjwWindow(bool isCollaboration,const std::wstring& location = L"/component/all"); 

        /// \brief 获取指定构件的标识信息
        /// \param projectId 项目库id
        /// \param componentId 构件项目id
        /// \return  返回最新版本的标识信息
        int GetLastVersionDirtyFlag(const std::wstring& projectId, const std::wstring& componentId);

        // 从公共库同步构件， 返回构件的id,categoryCode 的map
        bool SyncPublicComponents(const std::map<std::wstring, std::wstring> &idNameMap, const std::wstring& version,
            std::map<std::wstring, std::wstring>& idCategoryCodeMap);

        // 私有化环境上传公共构件到协同项目, 并下载到本地项目缓存
        std::map<std::wstring, ComponentInfos> AddComponentFromPublicForPrivate(const std::wstring & projectId,
            const std::map<std::wstring, std::wstring>& publicIdNameMap, const std::wstring &version, gcs::IGcsViewOptions *pViewOptions);
    private:
        std::shared_ptr<ILegend>  GetLegendStructure(std::tuple<std::wstring, std::wstring, int> legendIdGacPath);

        // 发送修改的构件到项目构件库
        std::wstring SendModifiedComponents(const std::wstring& projectId, const std::map<std::wstring, int>& modifiedIdMap2);
        // 发送删除的构件到项目构件库
        std::wstring SendDeletedComponents(const std::wstring& projectId, const std::map<std::wstring, int>& deletedIdMap2,
            std::map<std::wstring, int>& deletedSuccMap, std::map<std::wstring, int>& deletedFailedMap);
        // 发送新增GAC的构件到项目构件库
        // 对于上传成功项，返回旧id， 新id 和新name
        std::wstring SendAddedGACComponents(const std::wstring& projectId, const std::map<std::wstring, int>& addedFromGACIdMap2,
            std::vector<std::tuple<std::wstring, std::wstring, std::wstring>>& uploadedComponents);

        void AddPlaceHolderFilesToProjectForPrivate(const std::wstring & projectId, const std::vector<std::wstring>& projectLegendIds,
            const std::wstring &strProductLibraryFileName, const std::wstring &strProjectProduct2DFolder,
            std::map<std::wstring, GmepComponentPlaceHolderInfo>& uploadedProjectPlaceHolderInfo);

        // 私有化场景下，通过公共库图例Id， 对于本项目没有的图例，查询云端共享空间和项目图例库，若都没有，再上传到项目图例库
        void UploadProjectLegendsForPrivateEnv(const std::wstring &projectId, const std::vector<std::wstring>& publicPlaceHolderIdVec,
            const std::wstring& appVersion,
            const std::wstring& dbFilePath, // 此协同项目的db3
            const std::wstring& publicProductLibraryFileName, // 公共库的db3
            const std::wstring& publicProduct2DFolder,
            std::map<std::wstring, GmepComponentPlaceHolderInfo>& retSharePlaceHolderInfo,
            std::map<std::wstring, GmepComponentPlaceHolderInfo>& retProjectPlaceHolderInfo);
    private:
        static ProjectLocalComponentService *s_pInstance;

    };
}